/* 
  ESP32 MQTT安防系统 - 硬件控制布防完整版
  功能：
  1. GPIO22电平控制布防状态（HIGH=布防，LOW=撤防）
  2. GPIO23检测报警输入（低电平触发）
  3. 定时发送设备状态心跳（1Hz）
  4. 报警信息自动上报
  5. 状态LED指示当前布防状态
*/

/************************* 库引入 *************************/
#include <WiFi.h>          // WiFi通信库
#include <PubSubClient.h>  // MQTT客户端库
#include <ArduinoJson.h>   // JSON处理库（需安装v6+）

/************************* 硬件定义 *************************/
#define ALARM_PIN     23   // 报警检测引脚（低电平触发）
#define DEFENSE_PIN   0   // Boot按键（按下=接地）
#define STATUS_LED    2    // 状态指示灯（内置LED）

/************************* 新增防抖变量 *************************/
volatile unsigned long last_defense_time = 0;
const unsigned long debounce_delay = 200; // 防抖时间200ms

/************************* 网络配置 *************************/
const char* ssid = "feng";        // WiFi名称
const char* password = "qawsedrftg";// WiFi密码
const char* mqtt_server = "192.168.10.218"; // MQTT服务器IP
const int mqtt_port = 1883;            // MQTT端口

/************************* MQTT主题 *************************/
const char* topic_alarm = "efence/alarm";  // 报警主题
const char* topic_status = "efence/status";// 状态主题

/************************* 全局变量 *************************/
String device_id;               // 设备唯一ID（16位）
volatile bool alarm_flag = false; // 报警触发标志
volatile bool defense_status = false; // 布防状态
unsigned long last_heartbeat = 0;     // 最后心跳时间
const long heartbeat_interval = 1000; // 心跳间隔(ms)

WiFiClient espClient;           // WiFi客户端实例
PubSubClient client(espClient); // MQTT客户端实例

/************************* 中断服务函数 *************************/
IRAM_ATTR void handleAlarm() {
  /* 报警引脚中断处理（CHANGE触发）*/
  static unsigned long last_trig = 0;
  unsigned long now = millis();
  
  // 200ms防抖动处理
  if (now - last_trig > 200) {
    alarm_flag = true;
    last_trig = now;
  }
}

//修改了终端
IRAM_ATTR void handleDefense() {
  unsigned long now = millis();
  if (now - last_defense_time > debounce_delay) {
    defense_status = !defense_status; // 切换布防状态
    digitalWrite(STATUS_LED, defense_status);
    last_defense_time = now;
  }
}

/************************* 设备ID生成 *************************/
void generateDeviceID() {
  /* 基于MAC地址生成16位设备ID */
  uint8_t mac[6];
  WiFi.macAddress(mac);
  
  device_id = "";
  // 取MAC地址后3字节（更唯一）
  for(int i=3; i<6; i++){
    if(mac[i] < 0x10) device_id += "0";
    device_id += String(mac[i], HEX);
  }
  
  device_id.toUpperCase();       // 转换为大写
  while(device_id.length()<16) device_id += "0"; // 补零
  device_id = device_id.substring(0,16); // 截取16位
}

/************************* JSON生成函数 *************************/
String buildAlarmJson() {
  /* 构建报警JSON：{"id":"设备ID", "alarm":"0/1"} */
  StaticJsonDocument<200> doc;
  doc["id"] = device_id;
  doc["alarm"] = digitalRead(ALARM_PIN) ? "1" : "0"; 
  // HIGH时为"1"（报警），LOW为"0"
  String output;
  serializeJson(doc, output);
  return output;
}

String buildStatusJson() {
  /* 构建状态JSON：{"id":"设备ID", "status":"0/1"} */
  StaticJsonDocument<200> doc;
  doc["id"] = device_id;
  doc["status"] = defense_status ? "1" : "0";
  String output;
  serializeJson(doc, output);
  return output;
}

/************************* MQTT回调函数 *************************/
void callback(char* topic, byte* payload, unsigned int length) {
  /* MQTT消息到达回调（保留基础功能）*/
  String message;
  for (int i=0; i<length; i++) message += (char)payload[i];
  
  Serial.print("收到消息 [");
  Serial.print(topic);
  Serial.print("]: ");
  Serial.println(message);
  
  // 可扩展其他命令处理逻辑
}

/************************* MQTT重连 *************************/
void reconnect() {
  /* MQTT连接/重连管理 */
  while (!client.connected()) {
    Serial.print("尝试连接MQTT...");
    
    // 生成唯一客户端ID
    String clientId =device_id;
    
    if (client.connect(clientId.c_str())) {
      Serial.println("成功!");
      client.subscribe(topic_status); // 订阅状态主题（可选）
    } else {
      Serial.print("失败, rc=");
      Serial.print(client.state());
      Serial.println(" 5秒后重试...");
      delay(5000);
    }
  }
}

/************************* 初始化设置 *************************/
void setup() {
  Serial.begin(115200);
  
  // 初始化GPIO
  pinMode(ALARM_PIN, INPUT_PULLDOWN);   // 报警输入（下拉模式）
  pinMode(DEFENSE_PIN, INPUT_PULLUP); // 布防控制（上拉模式）
  pinMode(STATUS_LED, OUTPUT);        // 状态指示灯
  
  // 配置中断
  attachInterrupt(digitalPinToInterrupt(ALARM_PIN), handleAlarm, RISING);
  attachInterrupt(digitalPinToInterrupt(DEFENSE_PIN), handleDefense, CHANGE);
  
  pinMode(DEFENSE_PIN, INPUT_PULLUP); // 启用内部上拉电阻
  attachInterrupt(digitalPinToInterrupt(DEFENSE_PIN), handleDefense, FALLING);
  
  // 初始状态（根据硬件默认值设置）
  defense_status = false;
  digitalWrite(STATUS_LED, defense_status);

  // 连接WiFi
  WiFi.begin(ssid, password);
  Serial.print("连接WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi已连接, IP: " + WiFi.localIP().toString());
  
  // 生成设备ID
  generateDeviceID();
  Serial.print("设备ID: ");
  Serial.println(device_id);

  // 配置MQTT
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

/************************* 主循环 *************************/
void loop() {
  // 维持MQTT连接
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // 定时发送心跳（1Hz）
  if (millis() - last_heartbeat > heartbeat_interval) {
    client.publish(topic_status, buildStatusJson().c_str());
    last_heartbeat = millis();
    
    Serial.print("心跳: ");
    Serial.println(buildStatusJson());
  }

  // 处理报警触发
  if(alarm_flag && defense_status){
    client.publish(topic_alarm, buildAlarmJson().c_str());
    Serial.print("报警! ");
    Serial.println(buildAlarmJson());
    alarm_flag = false; // 清除标志
  }
}